import { config } from "@/inject/global";
import {
  WSBridgeDatagram,
  WSBridgeDatagramCategory,
  WSBridgeEventDatagram,
  WSBridgeInitDatagram,
} from "@common/meta";
import events from "@/inject/events";

export class WSBridge {
  private _socket: WebSocket;

  static _instance?: WSBridge;
  static Singleton() {
    if (!this._instance) {
      this._instance = new WSBridge();
    }
    return this._instance;
  }

  constructor() {
    const socket = new WebSocket(`ws://localhost:${config.WS_PORT}`);
    socket.onopen = () => {
      socket.send(
        JSON.stringify({
          category: WSBridgeDatagramCategory.CORE_CHANNEL_INIT,
          payload: {
            id: config.PAGE_ID,
            pluginId: config.PLUGIN_ID,
          },
        } as WSBridgeInitDatagram),
      );
    };
    socket.onerror = (err) => {
      console.error("ws bridge is error:", err);
    };
    socket.onclose = () => {
      console.warn("ws bridge is closed");
    };
    socket.onmessage = (ev) => {
      const datagram = JSON.parse(ev.data) as WSBridgeEventDatagram;
      if (datagram.category === WSBridgeDatagramCategory.CORE_EVENT) {
        const { data, event, sender } = datagram.payload;
        events.Remote.Accept.emit({
          data,
          sender,
          eventName: event,
        });
      }
    };

    this._socket = socket;

    events.Remote.Invoke.on(({ eventName, data, receiverId }) => {
      const datagram: WSBridgeEventDatagram = {
        category: WSBridgeDatagramCategory.CORE_EVENT,
        payload: {
          data,
          event: eventName,
          sender: config.PAGE_ID,
          receiverId,
        },
      };
      socket.send(JSON.stringify(datagram));
    });
  }

  send(category: WSBridgeDatagramCategory, payload: any) {
    this._socket.send(
      JSON.stringify({
        category,
        payload,
      } as WSBridgeDatagram),
    );
  }
}
